from abc import ABC, abstractmethod
from typing import Dict, Any, Optional
import asyncio
import uuid
import logging
from datetime import datetime

from ..entities import (
    CodeExecutionRequest, 
    ExecutionResult, 
    TaskStatus, 
    ExecutorConfig
)

logger = logging.getLogger(__name__)

class BaseExecutor(ABC):
    """执行器抽象基类"""
    
    def __init__(self, config: ExecutorConfig):
        self.config = config
        self.active_tasks: Dict[str, asyncio.Task] = {}
        self.task_results: Dict[str, ExecutionResult] = {}
        
    @abstractmethod
    async def prepare_environment(self, request: CodeExecutionRequest) -> Dict[str, Any]:
        """
        准备代码执行环境
        
        Args:
            request: 代码执行请求
            
        Returns:
            环境准备结果，包含环境信息
        """
        pass
    
    @abstractmethod
    async def apply_security_constraints(self, request: CodeExecutionRequest, env_info: Dict[str, Any]) -> Dict[str, Any]:
        """
        应用安全约束
        
        Args:
            request: 代码执行请求
            env_info: 环境信息
            
        Returns:
            安全约束配置
        """
        pass
    
    @abstractmethod
    async def execute_code(self, request: CodeExecutionRequest, env_info: Dict[str, Any], security_config: Dict[str, Any]) -> ExecutionResult:
        """
        执行代码
        
        Args:
            request: 代码执行请求
            env_info: 环境信息
            security_config: 安全配置
            
        Returns:
            执行结果
        """
        pass
    
    @abstractmethod
    async def cleanup_environment(self, env_info: Dict[str, Any]) -> None:
        """
        清理执行环境
        
        Args:
            env_info: 环境信息
        """
        pass
    
    async def run_task(self, request: CodeExecutionRequest, task_id: Optional[str] = None) -> ExecutionResult:
        """
        运行代码执行任务的完整流程
        
        Args:
            request: 代码执行请求
            task_id: 任务ID，如果未提供则自动生成
            
        Returns:
            执行结果
        """
        if task_id is None:
            task_id = str(uuid.uuid4())
        start_time = datetime.utcnow()
        
        result = ExecutionResult(
            task_id=task_id,
            status=TaskStatus.RUNNING,
            start_time=start_time,
            output=None,
            error=None,
            return_code=-1,
            execution_time=0.0,
            memory_usage=0,
            cpu_usage=0.0,
            end_time=None
        )
        
        env_info = {}
        
        try:
            logger.info(f"开始执行任务 {task_id}")
            
            # 1. 准备环境
            logger.debug(f"任务 {task_id}: 准备环境")
            env_info = await self.prepare_environment(request)
            
            # 2. 应用安全约束
            logger.debug(f"任务 {task_id}: 应用安全约束")
            security_config = await self.apply_security_constraints(request, env_info)
            
            # 3. 执行代码
            logger.debug(f"任务 {task_id}: 执行代码")
            result = await asyncio.wait_for(
                self.execute_code(request, env_info, security_config),
                timeout=request.timeout_seconds
            )
            
            result.task_id = task_id
            result.start_time = start_time
            result.end_time = datetime.utcnow()
            result.execution_time = (result.end_time - start_time).total_seconds()
            
            logger.info(f"任务 {task_id} 执行完成，状态: {result.status}")
            
        except asyncio.TimeoutError:
            result.status = TaskStatus.TIMEOUT
            result.error = f"任务超时（{request.timeout_seconds}秒）"
            result.end_time = datetime.utcnow()
            result.execution_time = request.timeout_seconds
            logger.warning(f"任务 {task_id} 执行超时")
            
        except Exception as e:
            result.status = TaskStatus.FAILED
            result.error = f"执行失败: {str(e)}"
            result.end_time = datetime.utcnow()
            result.execution_time = (result.end_time - start_time).total_seconds() if result.end_time and start_time else 0
            logger.error(f"任务 {task_id} 执行失败: {e}", exc_info=True)
            
        finally:
            # 4. 清理环境
            try:
                if env_info:
                    logger.debug(f"任务 {task_id}: 清理环境")
                    await self.cleanup_environment(env_info)
            except Exception as e:
                logger.error(f"任务 {task_id} 环境清理失败: {e}")
        
        # 存储结果
        self.task_results[task_id] = result
        return result
    
    async def get_task_result(self, task_id: str) -> Optional[ExecutionResult]:
        """
        获取任务执行结果
        
        Args:
            task_id: 任务ID
            
        Returns:
            执行结果或None
        """
        return self.task_results.get(task_id)
    
    def get_active_task_count(self) -> int:
        """
        获取当前活跃任务数量
        
        Returns:
            活跃任务数量
        """
        # 清理已完成的任务
        completed_tasks = [task_id for task_id, task in self.active_tasks.items() if task.done()]
        for task_id in completed_tasks:
            del self.active_tasks[task_id]
        
        return len(self.active_tasks)
    
    def can_accept_task(self) -> bool:
        """
        检查是否可以接受新任务
        
        Returns:
            是否可以接受新任务
        """
        return self.get_active_task_count() < self.config.max_concurrent_tasks
    
    async def submit_task(self, request: CodeExecutionRequest) -> str:
        """
        提交任务执行
        
        Args:
            request: 代码执行请求
            
        Returns:
            任务ID
            
        Raises:
            RuntimeError: 当执行器繁忙时
        """
        if not self.can_accept_task():
            raise RuntimeError("执行器繁忙，无法接受新任务")
        
        task_id = str(uuid.uuid4())
        task = asyncio.create_task(self.run_task(request))
        self.active_tasks[task_id] = task
        
        return task_id
    
    def get_status(self) -> Dict[str, Any]:
        """
        获取执行器状态
        
        Returns:
            执行器状态信息
        """
        return {
            "executor_type": self.__class__.__name__,
            "active_tasks": self.get_active_task_count(),
            "max_concurrent_tasks": self.config.max_concurrent_tasks,
            "total_completed_tasks": len(self.task_results),
            "can_accept_task": self.can_accept_task()
        } 